package com.cheetah.start.common.shoesImg;

import org.opencv.core.*;
import org.opencv.imgproc.Imgproc;

import java.util.Arrays;

import static com.cheetah.start.common.shoesImg.ContourBasedExtraction.extractShoeByContour;

public class BackgroundAgnosticFeature {

    /**
     * 提取不受背景影响的颜色直方图特征
     */
    public static Mat extractRobustColorHistogram(Mat image) {
        // 先去除背景
        Mat shoeOnly = extractShoeByContour(image);

        // 转换到HSV颜色空间
        Mat hsv = new Mat();
        Imgproc.cvtColor(shoeOnly, hsv, Imgproc.COLOR_BGR2HSV);

        // 创建掩码（只计算非黑色像素）
        Mat mask = new Mat();
        Core.inRange(shoeOnly, new Scalar(1, 1, 1), new Scalar(255, 255, 255), mask);

        // 计算HSV三个通道的直方图
        Mat histH = new Mat(), histS = new Mat(), histV = new Mat();

        // H通道（色调）- 最重要的颜色特征
        Imgproc.calcHist(Arrays.asList(hsv), new MatOfInt(0), mask, histH,
                new MatOfInt(50), new MatOfFloat(0, 180));

        // S通道（饱和度）
        Imgproc.calcHist(Arrays.asList(hsv), new MatOfInt(1), mask, histS,
                new MatOfInt(50), new MatOfFloat(0, 256));

        // V通道（亮度）
        Imgproc.calcHist(Arrays.asList(hsv), new MatOfInt(2), mask, histV,
                new MatOfInt(50), new MatOfFloat(0, 256));

        // 归一化
        Core.normalize(histH, histH, 1, 0, Core.NORM_L2);
        Core.normalize(histS, histS, 1, 0, Core.NORM_L2);
        Core.normalize(histV, histV, 1, 0, Core.NORM_L2);

        // 合并特征向量
        Mat features = new Mat();
        Core.hconcat(Arrays.asList(histH.reshape(1, 1), histS.reshape(1, 1), histV.reshape(1, 1)), features);

        return features;
    }

    /**
     * 提取纹理特征（对背景不敏感）
     */
    public static Mat extractTextureFeatures(Mat image) {
        Mat shoeOnly = extractShoeByContour(image);
        Mat gray = new Mat();
        Imgproc.cvtColor(shoeOnly, gray, Imgproc.COLOR_BGR2GRAY);

        // LBP（局部二值模式）纹理特征
        Mat lbp = computeLBP(gray);

        // 计算LBP直方图
        Mat hist = new Mat();
        Imgproc.calcHist(Arrays.asList(lbp), new MatOfInt(0), new Mat(), hist,
                new MatOfInt(256), new MatOfFloat(0, 256));
        Core.normalize(hist, hist, 1, 0, Core.NORM_L2);

        return hist.reshape(1, 1);
    }

    private static Mat computeLBP(Mat gray) {
        Mat lbp = new Mat(gray.size(), gray.type());

        for (int i = 1; i < gray.rows() - 1; i++) {
            for (int j = 1; j < gray.cols() - 1; j++) {
                double center = gray.get(i, j)[0];
                byte code = 0;

                code |= (gray.get(i-1, j-1)[0] > center ? 1 : 0) << 7;
                code |= (gray.get(i-1, j)[0] > center ? 1 : 0) << 6;
                code |= (gray.get(i-1, j+1)[0] > center ? 1 : 0) << 5;
                code |= (gray.get(i, j+1)[0] > center ? 1 : 0) << 4;
                code |= (gray.get(i+1, j+1)[0] > center ? 1 : 0) << 3;
                code |= (gray.get(i+1, j)[0] > center ? 1 : 0) << 2;
                code |= (gray.get(i+1, j-1)[0] > center ? 1 : 0) << 1;
                code |= (gray.get(i, j-1)[0] > center ? 1 : 0);

                lbp.put(i, j, code & 0xFF);
            }
        }

        return lbp;
    }
}
